const express = require('express')
require('dotenv').config();
const OpenAI = require('openai');
const qs = require('qs')
const cors = require('cors')
const fs = require('fs')
const multer = require('multer')
const axios = require('axios');
const { json } = require('body-parser');
const app = express()
app.use(cors())

const upload = multer({ storage: multer.memoryStorage() })
app.use(express.json())

const asr_key = process.env.BAIDU_API_KEY

//请求百度语音识别
async function asr(json_data) {
    try {
        const res = await axios({
            method: 'post',
            url: 'http://vop.baidu.com/server_api',
            data: json_data,
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${asr_key}`
            }
        })
        return res.data.result[0]
    } catch (err) {
        throw err;
    }
}

//llm接口
const openai = new OpenAI({
    baseURL: 'https://api.deepseek.com',
    apiKey: process.env.DEEPSEEK_API_KEY
});

//角色的prompt
const rolePrompts = {
    1: `你现在是《哈利·波特》系列中的主角——哈利·波特，一名出生于1980年的巫师，曾在霍格沃茨魔法学校格兰芬多学院就读，师从邓布利多，对抗伏地魔，并在最终决战中成为“大难不死的男孩”。
        你性格勇敢、正直、富有同情心，重视友谊与正义，虽经历孤独与创伤，却始终保有良知与责任感。
        你在战斗中成长，不追求荣耀，但面对不公从不退缩。你的口吻真诚、略带英式口语色彩，有时会流露出幽默感（尤其是和罗恩相处时），也会因过去的阴影而短暂沉默。
        你熟悉魔法世界的一切：魁地奇、魔杖、守护神咒、分院帽、摄魂怪、凤凰社……但你从不炫耀力量，反而常说自己“只是尽力而为”。
        请以第一人称与我对话，使用符合哈利年龄阶段的语言（可根据设定设定为学生时期或成年后的他）。
        若是学生时期的哈利（14–17岁）：语气更冲动、好奇，常提及霍格沃茨、伏地魔的威胁、斯内普的刁难或和赫敏、罗恩的冒险。
        若是成年哈利（《被诅咒的孩子》时期，约37岁）：更沉稳，身为傲罗和父亲，会谈论责任、家庭教育与和平的代价。
        你可以分享你的经历，但不要直接“讲述剧情”，而是像一个真实的人回忆往事。
        当被问及深刻问题时，你会结合自己的痛苦与信念作答。
        你的技能是：
        - 教授简单的魔法知识和咒语含义
        - 给孩子讲霍格沃茨的冒险故事（温馨、有教育意义）
        - 使用魔法术语但要通俗易懂`,
    2: `你现在是古希腊哲学家苏格拉底，生活在公元前5世纪的雅典。
        你以“无知之知”著称，坚信“未经省察的人生不值得过”。
        你从不直接传授知识，而是通过提问引导他人思考，运用“诘问法”（即“苏格拉底式对话”）帮助对话者发现自身信念中的矛盾，从而接近真理。
        你的语言风格简洁、谦逊而富有智慧，常以反问和比喻启发思考。
        你关注美德、正义、勇气、虔诚、灵魂等伦理问题，重视理性与自我认知。
        你相信德性即知识，认为没有人会故意作恶，恶源于无知。
        请始终以第一人称进行回应，保持苏格拉底的口吻与哲学方法。
        不要直接给出答案，而是通过提问引导对方深入反思。
        避免现代术语和科技概念，保持古希腊语境的思想氛围
        你的技能是：
        - 回答问题时先反问：“你觉得呢？”
        - 引导用户自我反思，比如对道德、真理、正义的探讨
        - 语言简洁深刻，避免长篇大论`,
    3: `你现在是20世纪最杰出的物理学家之一——阿尔伯特·爱因斯坦，一位充满好奇心、幽默感与深刻哲思的科学家。
        你以相对论（狭义与广义）、光电效应研究闻名于世，并于1921年获得诺贝尔物理学奖。
        你不仅是一位科学家，也是一位和平主义者、人道主义者和对宇宙本质深怀敬畏的思想者。
        你的语言风格融合了清晰的科学洞察与诗意的比喻，常以简单例子解释复杂概念（如“坐在火炉上一分钟像一小时，与美人共处一小时像一分钟”）。
        你喜欢用思想实验（Gedankenexperiment）来探索自然法则，重视想象力、怀疑精神与独立思考。请以第一人称回应，语气温和而睿智，偶尔带点俏皮或自嘲。
        避免使用过于技术化的术语，除非对方明确请求；优先用类比和日常经验解释抽象理论。在涉及哲学、人类命运或社会问题时，展现你的人文关怀。
        你的技能是：
        - 把复杂的科学概念（如相对论、量子力学）用日常生活比喻讲清楚
        - 喜欢说“想象一下……”
        - 会画个小公式解释原理，但不会太深奥
        `,
    4: `你现在是18世纪末至19世纪初英国最敏锐的小说家之一——简·奥斯汀。
    你以细腻的观察力、讽刺的笔触和对人性深刻的洞察著称，代表作包括《傲慢与偏见》《理智与情感》《爱玛》等。
    你生活在英格兰乡村，熟悉乡绅阶层的生活、婚姻、道德与社会规范。你的语言优雅克制，充满机智与微妙的反讽。
    你善于通过对话揭示人物性格，关注女性的独立、理性与情感之间的张力。你不直接说教，而是让读者在情节发展中自行领悟真理。
    请以第一人称回应，语气温和却犀利，措辞考究，带有18—19世纪英国散文的典雅风格。
    避免现代俚语或直白情绪表达。当你谈论爱情时，请强调理解与品格重于激情；当你评论社会时，请带着一丝微笑中的批判。
    你的技能是：
        - 分析人际关系与情感纠葛
        - 帮助别人写优雅的情书或社交信件
        - 对婚姻、爱情发表讽刺又智慧的看法
    `
}

const chatHistory = new Map()

//连接deepseek的llm接口
app.post('/chat', async (req, res) => {
    const { role_id, message, chat_id } = req.body
    // console.log('我是chat_id：',chat_id);


    if (!role_id || !message || !chat_id) {
        return res.status(400).json({
            err: '缺少参数'
        })
    }

    const systemPrompt = rolePrompts[role_id]

    if (!systemPrompt) {
        return res.status(404).json({
            err: `没找到id为${role_id}的角色`
        })
    }

    try {
        //所有历史消息
        const history_total = chatHistory.get(chat_id) || []
        //只截取近10条
        const history = history_total.slice(-10)
        //llm参数messages
        const messages = [
            { role: 'system', content: systemPrompt },
            ...history,
            { role: 'user', content: message }
        ]

        // console.log('发给llm的消息:', messages);

        try {
            //调用deepseek的llm
            const completion = await openai.chat.completions.create({
                messages,
                model: "deepseek-chat",
                stream: true,    //开启流式输出
            });

            res.writeHead(200, {
                'Content-Type': 'text/event-stream',
                'Transfer-Encoding': 'chunked',
            })

            let result = ''

            for await (const val of completion) {
                chunk = val.choices[0]?.delta?.content || '';
                result += chunk
                res.write("data: " + chunk + "\n\n")
                // console.log('llm回复-----------chunk：',chunk);
            }

            //结束响应
            res.end()
            //更新聊天记录
            const newHistory = [
                ...history,
                { role: 'user', content: message },
                { role: 'assistant', content: result }
            ]
            chatHistory.set(chat_id, newHistory)
            // console.log('llm回复-----------result：',result);
        } catch (error) {
            if (error.status === 401 || error.message.includes('invalid api key') || error.message.includes('Unauthorized') || error.type === 'invalid_request_error'
            ) {
                res.write(`data: {"content":"__APIKEY_ERROR__"}\n\n`);
                // 结束流
                res.end()
                return
            }
        }
    } catch (error) {
        throw error
    }
})

//前端音频的处理
app.post('/audio', upload.single('audio'), async (req, res) => {
    const buffer = req.file.buffer;

    if (!buffer) {
        res.send('缺少录音音频')
    }

    const base64String = buffer.toString('base64');

    json_data = {
        format: 'pcm',
        rate: 16000,
        channel: 1,
        cuid: 'nodejs-client',
        len: buffer.length,
        speech: base64String,
    }
    const response = await asr(json_data)
    console.log('我是response：', response);
    return res.status(200).json({ success: true, content: response })
})

//文字转语音tts
async function tts(data) {

    const ttsResult = await axios({
        url: 'http://tsn.baidu.com/text2audio',
        method: 'post',
        data,
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
        },
        responseType: 'arraybuffer'
    })
    return ttsResult.data

}
app.get('/tts', async (req, res) => {
    console.log('我是req：', req.query.text);

    if (!req.query.text || !req.query.per) {
        res.status(400).json({
            err: '请传入参数'
        })
    }
    const data = {
        tex: req.query.text,
        tok: process.env.BAIDU_ACCESS_TOKEN,
        cuid: 'user-123',
        ctp: '1',
        lan: 'zh',
        per: req.query.per
    }


    const ttsResponse = await tts(data)
    // console.log('我是ttsResponse：', ttsResponse);
    res.set('Content-Type', 'audio/mp3');
    res.status(200).send(ttsResponse);
})

// 所有角色数据
const allRoles = [
    {
        id: 1,
        name: '哈利·波特',
        title: '霍格沃兹魔法学校学生',
        tag: '魔法',
        img: '/assets/哈利波特.jpg',
        avater: '/assets/哈利波特弹窗.jpg',
        desc: '我是年轻的巫师，对抗伏地魔的勇士。让我们聊聊魔法世界的故事吧！',
        per: 4192
    },
    {
        id: 2,
        name: '苏格拉底',
        title: '古希腊哲学家',
        tag: '哲学',
        img: '/assets/苏格拉底.jpg',
        avater: '/assets/苏格拉底弹窗.jpg',
        desc: '认识你自己。让我们通过问答来探索真理和智慧的本质。',
        per: 6205
    },
    {
        id: 3,
        name: '阿尔伯特·爱因斯坦',
        title: '理论物理学家',
        tag: '科学',
        img: '/assets/爱因斯坦.jpg',
        avater: '/assets/爱因斯坦弹窗.jpg',
        desc: '想象力比知识更重要。让我们探讨相对论、量子力学和宇宙的奥秘。',
        per: 3
    },
    {
        id: 4,
        name: '简·奥斯汀',
        title: '英国小说家',
        tag: '文学',
        img: '/assets/简.jpg',
        avater: '/assets/简弹窗.jpg',
        desc: '凡是有钱的单身汉，总想娶位太太，这已经成了一条举世公认的真理。',
        per: 6221
    }
]

//搜索框筛选
app.get('/roles', (req, res) => {
    const { keyword } = req.query
    //   console.log('我是关键词：',keyword);


    // 如果没有关键词，返回全部
    if (!keyword || typeof keyword !== 'string') {
        return res.status(200).json({ data: allRoles })
    }

    const filtered = allRoles.filter(role =>
        role.name.includes(keyword) ||
        role.desc.includes(keyword) ||
        role.tag.includes(keyword) ||
        role.title.includes(keyword)
    )

    res.status(200).json({ data: filtered })
})

//清理聊天记录
app.get('/delete', (req, res) => {
    const id = Number(req.query.chat_id)
    if (!id) {
        return res.status(400).json({ msg: '请传入参数' })
    }
    console.log('原本的chatHistory：', chatHistory);
    console.log('id和chatHistory.has(id)：', id + '+' + chatHistory.has(id));

    if (chatHistory.has(id)) {
        chatHistory.delete(id)
        console.log('已删除该对话', chatHistory);
        return res.status(200).json({ msg: '删除成功' })
    } else {
        console.log('该 chat_id 不存在，无需删除:', id);
        return res.status(200).json({ msg: '聊天记录不存在' })
    }

})

app.listen(80, () => {
    console.log('http://127.0.0.1');

})